package common

import (
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

func GetCurrentDir() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		c, _ := os.Getwd()
		return c
	}
	return filepath.ToSlash(dir)
}

func GetAbsolutePath(path string) string {
	if strings.Index(path, "./") == 0 || strings.Index(path, ".\\") == 0 {
		r, _ := filepath.Abs(GetCurrentDir() + path[1:])
		return filepath.ToSlash(r)
	}
	r, _ := filepath.Abs(path)
	return filepath.ToSlash(r)
}

func GetDir(path string) string {
	if strings.Index(path, "./") == 0 || strings.Index(path, ".\\") == 0 {
		return filepath.ToSlash(filepath.Dir(GetCurrentDir() + path[1:]))
	}
	return filepath.ToSlash(filepath.Dir(path))
}

func EnsureDir(dir string) string {
	fullDir := GetAbsolutePath(dir)
	if IsExists(fullDir) {
		return fullDir
	}

	os.MkdirAll(fullDir, 777)
	return fullDir
}

func EnsureFilePath(filePath string) string {
	filePath = GetAbsolutePath(filePath)
	EnsureDir(GetDir(filePath))
	return filePath
}

func IsExists(path string) bool {
	_, err := os.Stat(path)
	if err != nil && os.IsNotExist(err) {
		return false
	}
	return true
}

func ReadAll(filePth string) ([]byte, error) {
	f, err := os.Open(filePth)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return ioutil.ReadAll(f)
}

func WriteAll(filePath string, data []byte) error {
	return ioutil.WriteFile(filePath, data, 0777)
}

//获取指定目录下的所有文件，不进入下一级目录搜索，可以匹配后缀过滤。
func ListDir(dirPth string, suffix string) (files []string, err error) {
	files = make([]string, 0, 10)

	dir, err := ioutil.ReadDir(dirPth)
	if err != nil {
		return nil, err
	}

	PthSep := string(os.PathSeparator)
	suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写

	for _, fi := range dir {
		if fi.IsDir() { // 忽略目录
			continue
		}
		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) { //匹配文件
			files = append(files, dirPth+PthSep+fi.Name())
		}
	}

	return files, nil
}

//获取指定目录及所有子目录下的所有文件，可以匹配后缀过滤。
func WalkDir(dirPth, suffix string) (files []string, err error) {
	files = make([]string, 0, 30)
	suffix = strings.ToUpper(suffix) //忽略后缀匹配的大小写

	err = filepath.Walk(dirPth, func(filename string, fi os.FileInfo, err error) error { //遍历目录
		//if err != nil { //忽略错误
		// return err
		//}

		if fi.IsDir() { // 忽略目录
			return nil
		}

		if strings.HasSuffix(strings.ToUpper(fi.Name()), suffix) {
			files = append(files, filename)
		}

		return nil
	})

	return files, err
}

func ReadFile(filePth string, blockSize *int, offset *int64, wg *WaitGroup, e *error, fn func([]byte, *int, *int64, bool, chan bool)) {
	go func() {
		if wg != nil {
			defer wg.Done()
		}

		f, err := os.Open(filePth)
		if err != nil {
			*e = errors.New("os.Open:" + err.Error())
			return
		}
		defer f.Close()

		quit := make(chan bool)
		defer close(quit)

	FOR:
		for {
			if *blockSize <= 0 {
				*blockSize = 1024
			}
			buf := make([]byte, *blockSize)
			n, err := f.ReadAt(buf, *offset)
			if err != nil {
				if err == io.EOF {
					fn(buf[:n], blockSize, offset, true, quit)
					return
				}
				*e = errors.New("f.ReadAt:" + err.Error())
				return
			}
			fn(buf[:n], blockSize, offset, false, quit)
			select {
			case <-quit:
				break FOR
			default:
			}
		}
	}()
}

func GetProjectRootDir(dir string) string {
	pdir := filepath.Join(os.Getenv("GOPATH"), "src", dir)
	pdir = EnsureDir(pdir)
	return pdir
}

func GetGoExec() string {
	g := filepath.Join(os.Getenv("GOROOT"), "bin", "go")
	switch runtime.GOOS {
	case "windows":
		return g + ".exe"
	}
	return g
}
